import type { App, Component, Ref } from 'vue'
import { createApp, h, ref } from 'vue'
import { NDrawer, NDrawerContent } from 'naive-ui'

interface DrawerOptions {
  title?: string
  width?: number | string
  placement?: 'top' | 'right' | 'bottom' | 'left'
  maskClosable?: boolean
  closable?: boolean
  // 其他 NaiveUI Drawer 支持的 props
  [key: string]
}

interface DrawerInstance {
  close: () => void
  updateProps: (props: Record<string, unknown>) => void
}

class DrawerManager {
  private static instance: DrawerManager
  private app: App | null = null
  private drawerVisible: Ref<boolean> = ref(false)
  private componentProps: Ref<Record<string, unknown>> = ref({})
  private currentComponent: Component | null = null
  private container: HTMLElement | null = null

  public static getInstance(): DrawerManager {
    if (!DrawerManager.instance) {
      DrawerManager.instance = new DrawerManager()
    }
    return DrawerManager.instance
  }

  public open(component: Component, options: DrawerOptions = {}, slots = {}): DrawerInstance {
    this.closeExistingDrawer()
    this.currentComponent = component
    this.container = document.createElement('div')
    document.body.appendChild(this.container)

    this.app = createApp({
      setup() {
        return () =>
          h(
            NDrawer,
            {
              show: DrawerManager.instance.drawerVisible.value,
              onUpdateShow: (val: boolean) => {
                if (!val) DrawerManager.instance.close()
              },
              ...options,
            },
            {
              default: () =>
                h(
                  NDrawerContent,
                  {
                    title: options?.title,
                    closable: options?.closable ?? true,
                  },
                  {
                    default: () => h(component, DrawerManager.instance.componentProps.value),
                    ...slots,
                  },
                ),
            },
          )
      },
    })

    this.app.mount(this.container)
    this.drawerVisible.value = true

    return {
      close: () => this.close(),
      updateProps: (props: Record<string, unknown>) => {
        this.componentProps.value = { ...this.componentProps.value, ...props }
      },
    }
  }

  private closeExistingDrawer() {
    if (this.app) {
      this.drawerVisible.value = false
      setTimeout(() => {
        this.cleanup()
      }, 300) // 等待动画结束
    }
  }

  public close() {
    this.drawerVisible.value = false
    setTimeout(() => {
      this.cleanup()
    }, 300)
  }

  private cleanup() {
    if (this.app) {
      this.app.unmount()
      this.app = null
    }
    if (this.container) {
      document.body.removeChild(this.container)
      this.container = null
    }
    this.currentComponent = null
    this.componentProps.value = {}
  }
}

export const drawer = DrawerManager.getInstance()
